package cruncher;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

import logic.PlayfairCipher;

public class TetragraphMap {
	private HashMap<String, Integer> tetragraphs = new HashMap<String, Integer>();
	private ArrayList<Entry<String, Integer>> entList = null;
	private PlayfairCipher cipher = null;
	private int[][][][] matrix = new int[26][32][32][32];
	
	public TetragraphMap(PlayfairCipher cipher)
	{
		this.cipher = cipher;
	}
	
	public TetragraphMap(PlayfairCipher cipher, String fileName)
	{
		this.cipher = cipher;
		loadFromFile(fileName);
	}
	
	private void putTetragraph(String tetragraph)
	{
		if(tetragraphs.containsKey(tetragraph))
		{
			tetragraphs.put(tetragraph, tetragraphs.get(tetragraph) + 1);
		}
		else
		{
			tetragraphs.put(tetragraph, 1);
			System.out.println("Word added : " + tetragraph);
		}
	}
	
	public void crunch(String text)
	{
		System.out.println("Orig text : " + text);
		text = text.toLowerCase();
		text = cipher.sanitizeString(text);
		text = cipher.getLanguage().doMappings(text);
		char[] cs = text.toCharArray();
		System.out.println("Crunching : " + text);
		for(int i = 0; i < cs.length - 4; i++)
		{
			putTetragraph(text.substring(i, i + 4));
		}
	}
	
	private void loadFromFile(String fileName)
	{
		try {
			Scanner s = new Scanner(new File(fileName));
			
			while(s.hasNext())
			{
				tetragraphs.put(s.next(), s.nextInt());
			}
			
			s.close();
			updateList();
		} catch (FileNotFoundException e) {
			System.out.println("Can't load file : " + fileName);
		}
	}
	
	public void saveToFile(String fileName)
	{
		try {
			PrintWriter pw = new PrintWriter(new File(fileName));
			updateList();
			
			for(Map.Entry<String, Integer> entry : entList)
			{
				pw.println(entry.getKey() + " " + entry.getValue());
			}
			
			pw.close();
		} catch (FileNotFoundException e) {
			System.out.println("Can't save file : " + fileName);
		}
	}
	
	public String getDigraph(int i)
	{
		return entList.get(i).getKey();
	}
	
	public int getNumDigraphs()
	{
		return entList.size();
	}
	
	public void crunchFile(String fileName)
	{
		try {
			Scanner s = new Scanner(new File(fileName));
			while(s.hasNext())
				crunch(s.nextLine());
			s.close();
		} catch (FileNotFoundException e) {
			System.out.println("Error opening file : " + fileName);
		}
		updateList();
	}
	
	private void updateList()
	{
		entList = new ArrayList<Map.Entry<String,Integer>>(tetragraphs.entrySet());
		Collections.sort(entList, new Comparator<Entry<String, Integer>>() {

			@Override
			public int compare(Entry<String, Integer> o1,
					Entry<String, Integer> o2) {
				return o2.getValue() - o1.getValue();
			}
		});
	}
	
	public void loadBinary(String fileName)
	{
		try {
			DataInputStream r = new DataInputStream(new FileInputStream(new File(fileName)));
			
			tetragraphs.clear();
			//char[] tetra = new char[4];
			for(int a = 0; a < 26; a++)
			{
				//tetra[0] = (char)(a + 97);
				for(int b = 0; b < 26; b++)
				{
					//tetra[1] = (char)(b + 97);
					for(int c = 0; c < 26; c++)
					{
						//tetra[2] = (char)(c + 97);
						for(int d = 0; d < 26; d++)
						{
							byte[] arr = new byte[2];
							r.read(arr);
							int f = (int)arr[0] + (int)arr[1] * 256;
							//tetra[3] = (char)(d + 97);	
							//tetragraphs.put(new String(tetra), f);
							//System.out.println(new String(tetra));
							matrix[a][b][c][d] = f;
						}
					}
				}
			}
		} catch (FileNotFoundException e) {
			System.out.println("Can't load file : " + fileName);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//System.out.println("Binary frequencies loaded!");
	}
	
	public void printContent()
	{
		if(entList == null) updateList();
		for(Map.Entry<String, Integer> entry : entList)
		{
			System.out.println(entry.getValue() + " : " + entry.getKey());
		}
	}
	
	public int evaluate(String text)
	{
		int score = 0;
		char[] carr = text.toCharArray();
		
		for(int i = 0; i < text.length() - 4; ++i)
		{
			//Integer freq = tetragraphs.get(text.substring(i, i + 4));
			//if(freq == null) freq = 0;
			//score += freq;
			//score += (int)Math.log(freq * 3);
			//score += freq;
			score += matrix[carr[i]-97][carr[i+1]-97][carr[i+2]-97][carr[i+3]-97];
		}
		return score;
	}
}
